perm filename PAGE16.WEB[MF,ALS] blob sn#786604 filedate 1985-02-15 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00003 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	@* Using the backpointers.
C00008 00003	@* Reading the postamble.
C00014 ENDMK
C⊗;
@* Using the backpointers.
The routines in this section of the program are brought into play so that
the the pages can be printed in reverse order.  First comes a routine for
finding the postamble.

@<Find the postamble, working back from the end@>=
n←dvi_length;
if n<53 then bad_dvi('only ',n:1,' bytes long');
@.only n bytes long@>
m←n-4;
repeat if m=0 then bad_dvi('all 223s');
@.all 223s@>
move_to_byte(m); k←get_byte; decr(m);
until k≠223;
if k≠id_byte then bad_dvi('ID byte is ',k:1);
@.ID byte is wrong@>
move_to_byte(m-3); q←signed_quad;
if (q<0)∨(q>m-33) then bad_dvi('post pointer ',q:1,' at byte ',m-3:1);
@.post pointer is wrong@>
move_to_byte(q); k←get_byte;
if k≠post then bad_dvi('byte ',q:1,' is not post');
@.byte n is not post@>
post_loc←q; first_backpointer←signed_quad;
if show_flag then print_ln(' first_backpointer=',first_backpointer:1)

@ Note that the last steps of the above code save the locations of the
the |post| byte and the final |bop|.  We had better declare these global
variables, together with another one that we will need shortly.

@<Glob...@>=
@!post_loc:integer; {byte location where the postamble begins}
@!first_backpointer:integer; {the pointer following |post|}
@!start_loc:integer; {byte location of the first page to process}

@ The next little routine shows how the backpointers can be followed
to move through a \.{DVI} file in reverse order. Ordinarily a \.{DVI}-reading
program would do this only if it wants to print the pages backwards or
if it wants to find a specified starting page that is not necessarily the
first page in the file; otherwise it would of course be simpler and faster
just to read the whole file from the beginning.

@<Count the pages and move to the starting page@>=
q←post_loc; p←first_backpointer; start_loc←-1;
if p<0 then in_postamble←true
else	begin repeat
		{now |q| points to a |post| or |bop| command; |p≥0| is prev pointer}
		if p>q-46 then
			bad_dvi('page link ',p:1,' after byte ',q:1);
@.page link wrong...@>
		q←p; move_to_byte(q); k←get_byte;
		if k=bop then incr(page_count)
		else bad_dvi('byte ',q:1,' is not bop');
@.byte n is not bop@>
		for k←0 to 9 do count[k]←signed_quad;
		if start_match then start_loc←q;
		p←signed_quad;
	until p<0;
	if start_loc<0 then abort('starting page number could not be found!');
@.starting page number...@>
	move_to_byte(start_loc+1); old_backpointer←start_loc;
	for k←0 to 9 do count[k]←signed_quad;
	p←signed_quad; started←true;
	end;
if page_count≠total_pages then
	print_ln('there are really ',page_count:1,' pages, not ',total_pages:1,'!')
@.there are really n pages@>

@ The following routine locates the postamble in order to read the value
of the |first_backpointer| but then processes the pages starting with the
last page so that the pages will be stacked properly by the \.{IMAGEN}.

@<Find the postamble then process the pages in reverse order@>=
n←dvi_length;
if n<53 then bad_dvi('only ',n:1,' bytes long');
@.only n bytes long@>
m←n-4;
repeat if m=0 then bad_dvi('all 223s');
@.all 223s@>
move_to_byte(m); k←get_byte; decr(m);
until k≠223;
if k≠id_byte then bad_dvi('ID byte is ',k:1);
@.ID byte is wrong@>
move_to_byte(m-3); q←signed_quad;
if (q<0)∨(q>m-33) then bad_dvi('post pointer ',q:1,' at byte ',m-3:1);
@.post pointer is wrong@>
move_to_byte(q); k←get_byte;
if k≠post then bad_dvi('byte ',q:1,' is not post');
@.byte n is not post@>
post_loc←q; first_backpointer←signed_quad;
new_backpointer←first_backpointer;  
if show_flag then print_ln(' first_backpointer=',first_backpointer:1);
while new_backpointer≠-1 do next_page;
while im_byte_no mod 4 ≠ 3 do im_byte(im_no_op);
im_byte(im_eof);
@* Reading the postamble.
Now imagine that we are reading the \.{DVI} file and positioned just
four bytes after the |post| command. That, in fact, is the situation,
when the following part of \.{DVIIMP} is called upon to read, translate,
and check the rest of the postamble.

@p procedure read_postamble;
var k:integer; {loop index}
@!p,@!q,@!m:integer; {general purpose registers}
begin showing←false; post_loc←cur_loc-5;
if show_flag then print_ln(' mstore indexes at ',f_i_r:1,',',s_i[f_i_r]:1);
if show_flag then print_ln('Postamble starts at byte ',post_loc:1,'.');
@.Postamble starts at byte n@>
if signed_quad≠numerator then
	print_ln('numerator doesn''t match the preamble!');
@.numerator doesn't match@>
if signed_quad≠denominator then
	print_ln('denominator doesn''t match the preamble!');
@.denominator doesn't match@>
if signed_quad≠mag then if new_mag=0 then
	print_ln('magnification doesn''t match the preamble!');
@.magnification doesn't match@>
max_v←signed_quad; max_h←signed_quad;@/
print('maxv=',max_v:1,', maxh=',max_h:1);@/
max_s←get_two_bytes; total_pages←get_two_bytes;@/
print_ln(', maxstackdepth=',max_s:1,', totalpages=',total_pages:1);
if out_mode<the_works then
	@<Compare the \\{lust} parameters with the accumulated facts@>;
@<Process the font definitions of the postamble@>;
@<Make sure that the end of the file is well-formed@>;
end;

@ No warning is given when |max_h_so_far| exceeds |max_h| by less than~100,
since 100 units is invisibly small; it's approximately the wavelength of
visible light, in the case of \TeX\ output. Rounding errors can be expected
to make |h| and |v| slightly more than |max_h| and |max_v|, every once in
a~while; hence small discrepancies are not cause for alarm.

@<Compare the \\{lust}...@>=
begin if max_v+99<max_v_so_far then
	print_ln('warning: observed maxv was ',max_v_so_far:1);
@.warning: observed maxv...@>
@.observed maxv was x@>
if max_h+99<max_h_so_far then
	print_ln('warning: observed maxh was ',max_h_so_far:1);
@.warning: observed maxh...@>
@.observed maxh was x@>
if max_s<max_s_so_far then
	print_ln('warning: observed maxstackdepth was ',max_s_so_far:1);
@.warning: observed maxstack...@>
@.observed maxstackdepth was x@>
if page_count≠total_pages then
	print_ln('there are really ',page_count:1,' pages, not ',total_pages:1,'!');
end
@.there are really n pages@>

@ When we get to the present code, the |post_post| command has
just been read.

@<Make sure that the end of the file is well-formed@>=
q←signed_quad;
if q≠post_loc then
	print_ln('bad postamble pointer in byte ',cur_loc-4:1,'!');
@.bad postamble pointer@>
m←get_byte;
if m≠id_byte then print_ln('identification in byte ',cur_loc-1:1,
@.identification...should be n@>
		' should be ',id_byte:1,'!');
k←cur_loc; m←223;
while (m=223)∧ not eof(dvi_file) do m←get_byte;
if not eof(dvi_file) then bad_dvi('signature in byte ',cur_loc-1:1,
@.signature...should be...@>
		' should be 223')
else if cur_loc<k+4 then
	print_ln('not enough signature bytes at end of file (',
@.not enough signature bytes...@>
		cur_loc-k:1,')');

@ @<Process the font definitions...@>=
repeat k←get_byte;
if (k≥fnt_def1)∧(k<fnt_def1+4) then
	begin p←first_par(k); define_font(p); print_ln(' '); k←nop;
	end;
until k≠nop;
if k≠post_post then
	print_ln('byte ',cur_loc-1:1,' is not postpost!')
@.byte n is not postpost@>